/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.lvyh.lightframe.core.consumer.route;


import com.lvyh.lightframe.common.util.CommonUtils;
import com.lvyh.lightframe.core.provider.ProviderHelper;
import com.lvyh.lightframe.core.provider.ProviderInfo;
import com.lvyh.lightframe.common.ext.Spi;
import com.lvyh.lightframe.core.invoke.request.RpcRequest;
import com.lvyh.lightframe.common.exception.RpcRuntimeException;

import java.util.List;
import java.util.Random;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

@Spi("round")
public class RoundLoadBalance extends LoadBalance {

    private ConcurrentMap<String, Integer> routeCountEachJob = new ConcurrentHashMap<String, Integer>();
    private long CACHE_VALID_TIME = 0;

    private int count(String serviceKey) {
        // cache clear
        if (System.currentTimeMillis() > CACHE_VALID_TIME) {
            routeCountEachJob.clear();
            CACHE_VALID_TIME = System.currentTimeMillis() + 24 * 60 * 60 * 1000;
        }

        // count++
        Integer count = routeCountEachJob.get(serviceKey);

        // During initialization, the active random is used once to relieve the pressure for the first time
        count = (count == null || count > 1000000) ? (new Random().nextInt(100)) : ++count;
        routeCountEachJob.put(serviceKey, count);
        return count;
    }

    public String doRoute(String serviceKey, TreeSet<String> addressSet) {
        String[] addressArr = addressSet.toArray(new String[addressSet.size()]);

        String finalAddress = addressArr[count(serviceKey) % addressArr.length];
        return finalAddress;
    }

    @Override
    public ProviderInfo doSelect(RpcRequest request, List<ProviderInfo> addressList) throws RpcRuntimeException {
        String serviceKey = CommonUtils.buildServiceUniqueCode(request.getClassName(), request.getVersion());

        TreeSet<String> addressSet = new TreeSet<String>(ProviderHelper.convert(addressList));
        String finalAddress = doRoute(serviceKey, addressSet);
        ProviderInfo providerInfo = new ProviderInfo(finalAddress);
        return providerInfo;
    }

}
